<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.6.6" />
<title>GRR Administrator Documentation</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */

/* Default font. */
body {
  font-family: Georgia,serif;
}

/* Title font. */
h1, h2, h3, h4, h5, h6,
div.title, caption.title,
thead, p.table.header,
#toctitle,
#author, #revnumber, #revdate, #revremark,
#footer {
  font-family: Arial,Helvetica,sans-serif;
}

body {
  margin: 1em 5% 1em 5%;
}

a {
  color: blue;
  text-decoration: underline;
}
a:visited {
  color: fuchsia;
}

em {
  font-style: italic;
  color: navy;
}

strong {
  font-weight: bold;
  color: #083194;
}

h1, h2, h3, h4, h5, h6 {
  color: #527bbd;
  margin-top: 1.2em;
  margin-bottom: 0.5em;
  line-height: 1.3;
}

h1, h2, h3 {
  border-bottom: 2px solid silver;
}
h2 {
  padding-top: 0.5em;
}
h3 {
  float: left;
}
h3 + * {
  clear: left;
}
h5 {
  font-size: 1.0em;
}

div.sectionbody {
  margin-left: 0;
}

hr {
  border: 1px solid silver;
}

p {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

ul, ol, li > p {
  margin-top: 0;
}
ul > li     { color: #aaa; }
ul > li > * { color: black; }

pre {
  padding: 0;
  margin: 0;
}

#author {
  color: #527bbd;
  font-weight: bold;
  font-size: 1.1em;
}
#email {
}
#revnumber, #revdate, #revremark {
}

#footer {
  font-size: small;
  border-top: 2px solid silver;
  padding-top: 0.5em;
  margin-top: 4.0em;
}
#footer-text {
  float: left;
  padding-bottom: 0.5em;
}
#footer-badges {
  float: right;
  padding-bottom: 0.5em;
}

#preamble {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
}
div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.admonitionblock {
  margin-top: 2.0em;
  margin-bottom: 2.0em;
  margin-right: 10%;
  color: #606060;
}

div.content { /* Block element content. */
  padding: 0;
}

/* Block element titles. */
div.title, caption.title {
  color: #527bbd;
  font-weight: bold;
  text-align: left;
  margin-top: 1.0em;
  margin-bottom: 0.5em;
}
div.title + * {
  margin-top: 0;
}

td div.title:first-child {
  margin-top: 0.0em;
}
div.content div.title:first-child {
  margin-top: 0.0em;
}
div.content + div.title {
  margin-top: 0.0em;
}

div.sidebarblock > div.content {
  background: #ffffee;
  border: 1px solid #dddddd;
  border-left: 4px solid #f0f0f0;
  padding: 0.5em;
}

div.listingblock > div.content {
  border: 1px solid #dddddd;
  border-left: 5px solid #f0f0f0;
  background: #f8f8f8;
  padding: 0.5em;
}

div.quoteblock, div.verseblock {
  padding-left: 1.0em;
  margin-left: 1.0em;
  margin-right: 10%;
  border-left: 5px solid #f0f0f0;
  color: #888;
}

div.quoteblock > div.attribution {
  padding-top: 0.5em;
  text-align: right;
}

div.verseblock > pre.content {
  font-family: inherit;
  font-size: inherit;
}
div.verseblock > div.attribution {
  padding-top: 0.75em;
  text-align: left;
}
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
div.verseblock + div.attribution {
  text-align: left;
}

div.admonitionblock .icon {
  vertical-align: top;
  font-size: 1.1em;
  font-weight: bold;
  text-decoration: underline;
  color: #527bbd;
  padding-right: 0.5em;
}
div.admonitionblock td.content {
  padding-left: 0.5em;
  border-left: 3px solid #dddddd;
}

div.exampleblock > div.content {
  border-left: 3px solid #dddddd;
  padding-left: 0.5em;
}

div.imageblock div.content { padding-left: 0; }
span.image img { border-style: none; }
a.image:visited { color: white; }

dl {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
dt {
  margin-top: 0.5em;
  margin-bottom: 0;
  font-style: normal;
  color: navy;
}
dd > *:first-child {
  margin-top: 0.1em;
}

ul, ol {
    list-style-position: outside;
}
ol.arabic {
  list-style-type: decimal;
}
ol.loweralpha {
  list-style-type: lower-alpha;
}
ol.upperalpha {
  list-style-type: upper-alpha;
}
ol.lowerroman {
  list-style-type: lower-roman;
}
ol.upperroman {
  list-style-type: upper-roman;
}

div.compact ul, div.compact ol,
div.compact p, div.compact p,
div.compact div, div.compact div {
  margin-top: 0.1em;
  margin-bottom: 0.1em;
}

tfoot {
  font-weight: bold;
}
td > div.verse {
  white-space: pre;
}

div.hdlist {
  margin-top: 0.8em;
  margin-bottom: 0.8em;
}
div.hdlist tr {
  padding-bottom: 15px;
}
dt.hdlist1.strong, td.hdlist1.strong {
  font-weight: bold;
}
td.hdlist1 {
  vertical-align: top;
  font-style: normal;
  padding-right: 0.8em;
  color: navy;
}
td.hdlist2 {
  vertical-align: top;
}
div.hdlist.compact tr {
  margin: 0;
  padding-bottom: 0;
}

.comment {
  background: yellow;
}

.footnote, .footnoteref {
  font-size: 0.8em;
}

span.footnote, span.footnoteref {
  vertical-align: super;
}

#footnotes {
  margin: 20px 0 20px 0;
  padding: 7px 0 0 0;
}

#footnotes div.footnote {
  margin: 0 0 5px 0;
}

#footnotes hr {
  border: none;
  border-top: 1px solid silver;
  height: 1px;
  text-align: left;
  margin-left: 0;
  width: 20%;
  min-width: 100px;
}

div.colist td {
  padding-right: 0.5em;
  padding-bottom: 0.3em;
  vertical-align: top;
}
div.colist td img {
  margin-top: 0.3em;
}

@media print {
  #footer-badges { display: none; }
}

#toc {
  margin-bottom: 2.5em;
}

#toctitle {
  color: #527bbd;
  font-size: 1.1em;
  font-weight: bold;
  margin-top: 1.0em;
  margin-bottom: 0.1em;
}

div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
  margin-top: 0;
  margin-bottom: 0;
}
div.toclevel2 {
  margin-left: 2em;
  font-size: 0.9em;
}
div.toclevel3 {
  margin-left: 4em;
  font-size: 0.9em;
}
div.toclevel4 {
  margin-left: 6em;
  font-size: 0.9em;
}

span.aqua { color: aqua; }
span.black { color: black; }
span.blue { color: blue; }
span.fuchsia { color: fuchsia; }
span.gray { color: gray; }
span.green { color: green; }
span.lime { color: lime; }
span.maroon { color: maroon; }
span.navy { color: navy; }
span.olive { color: olive; }
span.purple { color: purple; }
span.red { color: red; }
span.silver { color: silver; }
span.teal { color: teal; }
span.white { color: white; }
span.yellow { color: yellow; }

span.aqua-background { background: aqua; }
span.black-background { background: black; }
span.blue-background { background: blue; }
span.fuchsia-background { background: fuchsia; }
span.gray-background { background: gray; }
span.green-background { background: green; }
span.lime-background { background: lime; }
span.maroon-background { background: maroon; }
span.navy-background { background: navy; }
span.olive-background { background: olive; }
span.purple-background { background: purple; }
span.red-background { background: red; }
span.silver-background { background: silver; }
span.teal-background { background: teal; }
span.white-background { background: white; }
span.yellow-background { background: yellow; }

span.big { font-size: 2em; }
span.small { font-size: 0.6em; }

span.underline { text-decoration: underline; }
span.overline { text-decoration: overline; }
span.line-through { text-decoration: line-through; }


/*
 * xhtml11 specific
 *
 * */

tt {
  font-family: monospace;
  font-size: inherit;
  color: navy;
}

div.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
div.tableblock > table {
  border: 3px solid #527bbd;
}
thead, p.table.header {
  font-weight: bold;
  color: #527bbd;
}
p.table {
  margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
  border-style: none;
}
div.tableblock > table[frame="hsides"] {
  border-left-style: none;
  border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
  border-top-style: none;
  border-bottom-style: none;
}


/*
 * html5 specific
 *
 * */

.monospaced {
  font-family: monospace;
  font-size: inherit;
  color: navy;
}

table.tableblock {
  margin-top: 1.0em;
  margin-bottom: 1.5em;
}
thead, p.tableblock.header {
  font-weight: bold;
  color: #527bbd;
}
p.tableblock {
  margin-top: 0;
}
table.tableblock {
  border-width: 3px;
  border-spacing: 0px;
  border-style: solid;
  border-color: #527bbd;
  border-collapse: collapse;
}
th.tableblock, td.tableblock {
  border-width: 1px;
  padding: 4px;
  border-style: solid;
  border-color: #527bbd;
}

table.tableblock.frame-topbot {
  border-left-style: hidden;
  border-right-style: hidden;
}
table.tableblock.frame-sides {
  border-top-style: hidden;
  border-bottom-style: hidden;
}
table.tableblock.frame-none {
  border-style: hidden;
}

th.tableblock.halign-left, td.tableblock.halign-left {
  text-align: left;
}
th.tableblock.halign-center, td.tableblock.halign-center {
  text-align: center;
}
th.tableblock.halign-right, td.tableblock.halign-right {
  text-align: right;
}

th.tableblock.valign-top, td.tableblock.valign-top {
  vertical-align: top;
}
th.tableblock.valign-middle, td.tableblock.valign-middle {
  vertical-align: middle;
}
th.tableblock.valign-bottom, td.tableblock.valign-bottom {
  vertical-align: bottom;
}


/*
 * manpage specific
 *
 * */

body.manpage h1 {
  padding-top: 0.5em;
  padding-bottom: 0.5em;
  border-top: 2px solid silver;
  border-bottom: 2px solid silver;
}
body.manpage h2 {
  border-style: none;
}
body.manpage div.sectionbody {
  margin-left: 3em;
}

@media print {
  body.manpage div#toc { display: none; }
}
@media screen {
  body {
    max-width: 50em; /* approximately 80 characters wide */
    margin-left: 16em;
  }

  #toc {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 13em;
    padding: 0.5em;
    padding-bottom: 1.5em;
    margin: 0;
    overflow: auto;
    border-right: 3px solid #f8f8f8;
    background-color: white;
  }

  #toc .toclevel1 {
    margin-top: 0.5em;
  }

  #toc .toclevel2 {
    margin-top: 0.25em;
    display: list-item;
    color: #aaaaaa;
  }

  #toctitle {
    margin-top: 0.5em;
  }
}
</style>
<script type="text/javascript">
/*<![CDATA[*/
var asciidoc = {  // Namespace.

/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////

/* Author: Mihai Bazon, September 2002
 * http://students.infoiasi.ro/~mishoo
 *
 * Table Of Content generator
 * Version: 0.4
 *
 * Feel free to use this script under the terms of the GNU General Public
 * License, as long as you do not remove or alter this notice.
 */

 /* modified by Troy D. Hanson, September 2006. License: GPL */
 /* modified by Stuart Rackham, 2006, 2009. License: GPL */

// toclevels = 1..4.
toc: function (toclevels) {

  function getText(el) {
    var text = "";
    for (var i = el.firstChild; i != null; i = i.nextSibling) {
      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
        text += i.data;
      else if (i.firstChild != null)
        text += getText(i);
    }
    return text;
  }

  function TocEntry(el, text, toclevel) {
    this.element = el;
    this.text = text;
    this.toclevel = toclevel;
  }

  function tocEntries(el, toclevels) {
    var result = new Array;
    var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
    // Function that scans the DOM tree for header elements (the DOM2
    // nodeIterator API would be a better technique but not supported by all
    // browsers).
    var iterate = function (el) {
      for (var i = el.firstChild; i != null; i = i.nextSibling) {
        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
          var mo = re.exec(i.tagName);
          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
          }
          iterate(i);
        }
      }
    }
    iterate(el);
    return result;
  }

  var toc = document.getElementById("toc");
  if (!toc) {
    return;
  }

  // Delete existing TOC entries in case we're reloading the TOC.
  var tocEntriesToRemove = [];
  var i;
  for (i = 0; i < toc.childNodes.length; i++) {
    var entry = toc.childNodes[i];
    if (entry.nodeName == 'div'
     && entry.getAttribute("class")
     && entry.getAttribute("class").match(/^toclevel/))
      tocEntriesToRemove.push(entry);
  }
  for (i = 0; i < tocEntriesToRemove.length; i++) {
    toc.removeChild(tocEntriesToRemove[i]);
  }

  // Rebuild TOC entries.
  var entries = tocEntries(document.getElementById("content"), toclevels);
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if (entry.element.id == "")
      entry.element.id = "_toc_" + i;
    var a = document.createElement("a");
    a.href = "#" + entry.element.id;
    a.appendChild(document.createTextNode(entry.text));
    var div = document.createElement("div");
    div.appendChild(a);
    div.className = "toclevel" + entry.toclevel;
    toc.appendChild(div);
  }
  if (entries.length == 0)
    toc.parentNode.removeChild(toc);
},


/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////

/* Based on footnote generation code from:
 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
 */

footnotes: function () {
  // Delete existing footnote entries in case we're reloading the footnodes.
  var i;
  var noteholder = document.getElementById("footnotes");
  if (!noteholder) {
    return;
  }
  var entriesToRemove = [];
  for (i = 0; i < noteholder.childNodes.length; i++) {
    var entry = noteholder.childNodes[i];
    if (entry.nodeName == 'div' && entry.getAttribute("class") == "footnote")
      entriesToRemove.push(entry);
  }
  for (i = 0; i < entriesToRemove.length; i++) {
    noteholder.removeChild(entriesToRemove[i]);
  }

  // Rebuild footnote entries.
  var cont = document.getElementById("content");
  var spans = cont.getElementsByTagName("span");
  var refs = {};
  var n = 0;
  for (i=0; i<spans.length; i++) {
    if (spans[i].className == "footnote") {
      n++;
      var note = spans[i].getAttribute("data-note");
      if (!note) {
        // Use [\s\S] in place of . so multi-line matches work.
        // Because JavaScript has no s (dotall) regex flag.
        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
        spans[i].innerHTML =
          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
        spans[i].setAttribute("data-note", note);
      }
      noteholder.innerHTML +=
        "<div class='footnote' id='_footnote_" + n + "'>" +
        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
        n + "</a>. " + note + "</div>";
      var id =spans[i].getAttribute("id");
      if (id != null) refs["#"+id] = n;
    }
  }
  if (n == 0)
    noteholder.parentNode.removeChild(noteholder);
  else {
    // Process footnoterefs.
    for (i=0; i<spans.length; i++) {
      if (spans[i].className == "footnoteref") {
        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
        href = href.match(/#.*/)[0];  // Because IE return full URL.
        n = refs[href];
        spans[i].innerHTML =
          "[<a href='#_footnote_" + n +
          "' title='View footnote' class='footnote'>" + n + "</a>]";
      }
    }
  }
},

install: function(toclevels) {
  var timerId;

  function reinstall() {
    asciidoc.footnotes();
    if (toclevels) {
      asciidoc.toc(toclevels);
    }
  }

  function reinstallAndRemoveTimer() {
    clearInterval(timerId);
    reinstall();
  }

  timerId = setInterval(reinstall, 500);
  if (document.addEventListener)
    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
  else
    window.onload = reinstallAndRemoveTimer;
}

}
asciidoc.install(2);
/*]]>*/
</script>
</head>
<body class="article">
<div id="header">
<h1>GRR Administrator Documentation</h1>
<div id="toc">
  <div id="toctitle">Table of Contents</div>
  <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>This document is intended for administrators who wish to deploy and manage GRR
in an enterprise. It is also applicable for anyone who wants to try it out.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_deploying_the_grr_server">Deploying the GRR server.</h2>
<div class="sectionbody">
<div class="paragraph"><p>Documentation on how deploy the GRR server on an Ubuntu system is currently
covered in the wiki here:
<a href="http://code.google.com/p/grr/wiki/ServerInstallation">http://code.google.com/p/grr/wiki/ServerInstallation</a></p></div>
</div>
</div>
<div class="sect1">
<h2 id="_key_management">Key Management</h2>
<div class="sectionbody">
<div class="paragraph"><p>GRR requires multiple key pairs. These are used to:</p></div>
<div class="ulist"><ul>
<li>
<p>
Sign the client certificates for enrollment.
</p>
</li>
<li>
<p>
Sign and decrypt messages from the client.
</p>
</li>
<li>
<p>
Sign code and drivers sent to the client.
</p>
</li>
</ul></div>
<div class="paragraph"><p>These keys can be generated using the config_updater script normally installed
in the path as grr_config_updater using the generate_keys command.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:$ sudo grr_config_updater generate_keys
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
Generating executable signing key
..............+++
.....+++
Generating driver signing key
..................................................................+++
.............................................................+++
Generating CA keys
Generating Server keys
Generating Django Secret key (used for xsrf protection etc)
db@host:$</tt></pre>
</div></div>
</div>
</div>
<div class="sect1">
<h2 id="_user_management">User Management</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_security_managers_and_user_managers">Security Managers and User Managers.</h3>
<div class="paragraph"><p>GRR supports the ideas of a User Manager and a separate Security Manager.
The User Manager handles authentication, setting passwords and managing labels
for those users.
The Security Manager (Datastore.security_manager config option) handles
authorizing those users to resources based on a set of rules.</p></div>
<div class="paragraph"><p>By default GRR will use the ConfigBasedUserManager which manages the users in a
basic format inside the ["Users"] section of the configuration file.</p></div>
<div class="paragraph"><p>The default Security Manager is the BasicAccessControlManager. This manager
provides rudimentary Admin/Non-Admin functionality, but very little else. See
the Auditing section for a discussion on the FullAccessControlManager.</p></div>
</div>
<div class="sect2">
<h3 id="_adding_and_updating_users">Adding and Updating Users.</h3>
<div class="paragraph"><p>If you are using the ConfigBasedUserManager (default) then you can add users
with config updater.</p></div>
<div class="paragraph"><p>To add the user joe as an admin:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:~$ sudo grr_config_updater add_user --username joe
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
Please enter password for user joe:
db@host:~$</tt></pre>
</div></div>
<div class="paragraph"><p>To add the user bob as a non-admin, with password test1234 and with the
additional labels label1,label2:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:~$ sudo grr_config_updater add_user --username bob --noadmin --password
test1234 --label label1 --label label2
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
db@host:~$</tt></pre>
</div></div>
<div class="paragraph"><p>To then update bob to an admin and set the labels to just label1</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:~$ sudo grr_config_updater update_user --username bob --label label1
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
db@host:~$</tt></pre>
</div></div>
</div>
<div class="sect2">
<h3 id="_authentication_to_the_admin_ui">Authentication to the Admin UI.</h3>
<div class="paragraph"><p>Given the sensitivity of the data that GRR ends up holding, it is important to
protect access to it. The AdminUI by default uses weak digest authentication,
based on the users stored in the config file.
However, we support the idea of a Webauth Manager
(AdminUI.webauth_manager config option). This allows for customization to use an
SSO or SAML based authentication mechanism. However, while we try and make it
easy to integrate, this kind of auth is not currently built into GRR.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_security_considerations">Security Considerations</h2>
<div class="sectionbody">
<div class="paragraph"><p>Because GRR is designed to be deployed on the Internet and provides very
valuable functionality to an attacker, it comes with a number of security
considerations to think about before deployment. This section will cover the key
security mechanisms and the options you have.</p></div>
<div class="sect2">
<h3 id="_communication_security">Communication Security.</h3>
<div class="paragraph"><p>GRR communication happens using signed and encrypted protobuf messages. We use
1024 bit RSA keys to protect symmettric AES256 encryption. The security of the
system does not rely on SSL transport for communication security. This enables
easy replacement of the comms protocol with non-http mechanisms such as UDP
packets.</p></div>
<div class="paragraph"><p>The communications use a CA and server public key pair generated on server
install. The CA public key is deployed to the client so that it can ensure it
is communicating with the correct server. If these keys are not kept secure,
anyone with MITM capability can intercept communications and take control of
your clients. Additionally, if you lose these keys, you lose the ability to
communicate with your clients.</p></div>
<div class="paragraph"><p>Full details of this protocol and the security properties can be found in the
<a href="implementation.html">Implementation document</a>.</p></div>
</div>
<div class="sect2">
<h3 id="_driver_code_signing_and_ca_keys">Driver, Code Signing and CA Keys.</h3>
<div class="paragraph"><p>In addition to the CA and Server key pairs, GRR maintains a set of code
signing and driver signing keys.
By default GRR aims to provide only read-only actions, this means that GRR is
unlikely to modify evidence, and cannot trivially be used to take control of
systems running the agent <span class="footnote"><br />[Read only access many not give direct code
exec, but may well provide it indirectly via read access to important keys and
passwords on disk or in memory.]<br /></span>.
However, there are a number of use cases where it makes sense to have GRR
execute arbitrary code as explained in the section Deploying custom drivers
and code.</p></div>
<div class="paragraph"><p>However, as part of the GRR design, we decided that administrative control of
the GRR server shouldn&#8217;t trivially lead to code execution on the clients. As
such, we have a separate set of keys for driver signing and code signing.
For a driver to be loaded, or binary to be run the code has to be signed by
the specific key, the client will confirm this signature before execution.</p></div>
<div class="paragraph"><p>In the default install, the driver and code signing private keys are not
passphrase protected. In a secure environment we strongly recommended
generating and storing these keys off the GRR server and doing offline
signing every time this functionality is required, or at a minimum setting
passphrases which are required on every use.</p></div>
</div>
<div class="sect2">
<h3 id="_agent_protection">Agent Protection.</h3>
<div class="paragraph"><p>The open source agent does not contain protection against being disabled by
administrator/root on the machine. E.g. on Windows, if an attacker stops the
service, the agent will stop and will no longer be reachable.
Currently, it is up to the deployer of GRR to provide more protection for the
service.</p></div>
</div>
<div class="sect2">
<h3 id="_obfuscation">Obfuscation.</h3>
<div class="paragraph"><p>If every deployment in the world is running from the same location and the
same code, e.g. c:\program files\grr\grr.exe, it becomes a pretty obvious
thing for an attacker to look for and disable. Luckily the attacker has the
same problem an investigator has in finding malware on a system, and we can
use the same techniques to protect the client.
One of the key benefits of having an open architecture is that customization
of the client and server is easy, and completely within your control.</p></div>
<div class="paragraph"><p>For a test, or low security deployment, using the defaults open source agents
is fine. However, in a secure environment we strongly recommend using some
form of obfuscation.</p></div>
<div class="paragraph"><p>This can come in many forms, but to give some examples:</p></div>
<div class="ulist"><ul>
<li>
<p>
Changing service, and binary names
</p>
</li>
<li>
<p>
Changing registry keys
</p>
</li>
<li>
<p>
Obfuscating the underlying python code
</p>
</li>
<li>
<p>
Using a packer to obfuscate the resulting binary
</p>
</li>
<li>
<p>
Implementing advanced protective or obfuscation functionality such as those
 used in rootkits
</p>
</li>
<li>
<p>
Implementing watchers to monitor for failure of the client
</p>
</li>
</ul></div>
<div class="paragraph"><p>GRR does not include any obfuscation mechanisms by default. But we attempt to
make this relatively easy by controlling the build process through the
configuration file.</p></div>
</div>
<div class="sect2">
<h3 id="_enrollment">Enrollment.</h3>
<div class="paragraph"><p>In the default setup, clients can register to the GRR server with no prior
knowledge. This means that anyone who has a copy of the GRR agent, and knows
the address of your GRR server can register their client to your deployment.
This significantly eases deployment, and is generally considered low risk as
the client has no control or trust on the server.
However, it does introduce some risk, in particular:
- If there are flows or hunts you deploy to the entire fleet, a malicious
client may receive them. These could give away information about what you are
searching for.
- Clients are allowed to send some limited messages to the server without
prompting, these are called Well Known flows. By default these can be used
to send log messages, or errors. A malicious client using these could fill up
logs and disk space.
- If you have custom Well Known Flows that perform interesting actions. You need
 to be aware that untrusted clients can call them. Most often this could result
 in a DoS condition, e.g. through a client sending multiple install failure or
 client crash messages.</p></div>
<div class="paragraph"><p>In many environments this risk is unwarranted, so we suggest implementing
further authorization in the Enrollment Flow using some information that only
your client knows, to authenticate it before allowing it to become a
registered client.</p></div>
<div class="paragraph"><p>Note that this does not give someone the ability to overwrite data from
another client, as client name collisions are protected.</p></div>
</div>
<div class="sect2">
<h3 id="_server_security">Server Security.</h3>
<div class="paragraph"><p>The http server is designed to be exposed to the Internet, but there is no
reason for the other components in the GRR system to be.</p></div>
<div class="paragraph"><p>The Administration UI by default listens on all interfaces, and is protected by
only basic authentication configured via the --htpasswd parameter. We strongly
recommend putting the UI on SSL and IP limiting the clients that can connect.
The best way to do this normally is by hosting it inside Apache via wsgi,
using Apache to provide the SSL and other protection measures.</p></div>
</div>
<div class="sect2">
<h3 id="_auditing">Auditing.</h3>
<div class="paragraph"><p>By default GRR currently only offers limited audit logs in the /var/log/
directory. However, the system is designed to allow for deployment of extensive
auditing capabilities through the Security Manager.</p></div>
<div class="paragraph"><p>The idea is that we have a gateway process, and the Admin UI and any console
access is brokered through the gateway. The gateway is the only access to the
datastore and it audits all access and can provide intelligent access control.
This is implemented in the FullAccessControlManager.</p></div>
<div class="paragraph"><p>Using this allows for sensible access control, e.g. another user must authorize
access before someone is given access to a machine, or an admin must authorize
before a hunt is run.</p></div>
<div class="paragraph"><p>These capabilities are powerful but add significant complexity to deployment so
they are not currently released  (Mar 2013). If you are interested in this
functionality please just email the devs and we can release it.</p></div>
</div>
<div class="sect2">
<h3 id="_grr_security_checklist">GRR Security Checklist.</h3>
<div class="ulist"><div class="title">For all deployments</div><ul>
<li>
<p>
Generate new CA/server keys on initial install. Back up these keys somewhere
securely.
</p>
</li>
<li>
<p>
Ensure the GRR Administrative UI interface is not exposed to the Internet
and is protected.
</p>
</li>
</ul></div>
<div class="ulist"><div class="title">For a high security environment</div><ul>
<li>
<p>
Introduce controls on enrollment to protect the server from unauthorized
clients.
</p>
</li>
<li>
<p>
Produce obfuscated clients.
</p>
</li>
<li>
<p>
Regenerate code and driver signing keys with passphrases.
</p>
</li>
<li>
<p>
Run the http server serving clients on a separate machine to the workers.
</p>
</li>
<li>
<p>
Introduce a stronger AdminUI sign in mechanism and use the
FullAccessControlManager.
</p>
</li>
<li>
<p>
Ensure the Administrative UI and it is SSL protected.
</p>
</li>
<li>
<p>
Ensure the database server is using strong passwords and is well protected.
</p>
</li>
</ul></div>
</div>
<div class="sect2">
<h3 id="_managing_the_datastore">Managing the Datastore</h3>
<div class="paragraph"><p>GRR currently ships with two usable datastores, MongoDB and MySQL, and an extra
in memory only test datastore FakeDataStore.</p></div>
<div class="paragraph"><p>By default GRR will use the MongoDataStore and expect to find it on localhost.
You can configure it in the config file, e.g.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>[MongoDataStore]
server = mongodb.host.example.com
port = 27017
db_name = grr</tt></pre>
</div></div>
<div class="paragraph"><p>We also provide a useful script [scripts/database_reset.sh] to drop the Mongo
database which is handy while testing things.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_performance">Performance</h2>
<div class="sectionbody">
<div class="paragraph"><p>GRR is designed to scale linearly, which it mostly does. It has been run in test
environments wtih with greater than 100,000 clients reporting and hunting
without problems. However, this depends significantly on the datastore
implementation, how it is being run, and the hardware it is running on.</p></div>
<div class="paragraph"><p>As of April 2013, we don&#8217;t have a clear set of metrics on performance in the
main release, however there is work being done to create these.</p></div>
<div class="sect2">
<h3 id="_deployment_performance_factors">Deployment Performance Factors</h3>
<div class="paragraph"><p>The key issue with performance generally relates to how the server is deployed.</p></div>
<div class="ulist"><ul>
<li>
<p>
If you are running from the prepackaged release you are likely running the
  grr_server.py binary. This binary runs all components in a single process,
  which means you are using a single core and it will perform badly. We do this
  to make life easy for first time users. In production you need to run each
  component separately (see /etc/init/grr*) in its own process (this will also
  help with more intelligent logging). You can switch on upstart based systems
  easily using the script in scripts/initctl_switch.sh.
</p>
</li>
<li>
<p>
Additionally, you will probably want to run more than one worker. In a large
  deployment where you are running numerous hunts it makes sense to run 20+
  workers. As long as the datastore scales, the more workers you have the faster
  things get done. Each worker will use 1 core maximum, so running up multiple
  on the same box can make sense.
</p>
</li>
<li>
<p>
Also, the frontend http server can be a significant bottleneck. By default we
  ship with a simple http server, but this is single process, written in python
  which means it may have thread lock issues. To get better performance you will
  need to run the http server with the wsgi_server in the tools directory from
  inside a faster web server such as Apache. See section below for how.
</p>
</li>
<li>
<p>
As well as having a better performing http server, if you are moving a lot of
  traffic you probably want to run multiple http servers. Again, assuming your
  datastore handles it, these should scale linearly.
</p>
</li>
<li>
<p>
The admin UI and enroller components should have less load on them, depending
  on your use case, but you can run as many as you want for redundancy.
</p>
</li>
</ul></div>
</div>
<div class="sect2">
<h3 id="_datastore_performance">Datastore Performance</h3>
<div class="paragraph"><p>If you are not CPU bound on the individual components (workers, http server)
then the key performance differentiator will be the datastore. At the moment
we ship with a Mysql and a Mongo datastore.</p></div>
<div class="ulist"><ul>
<li>
<p>
The Mongo datastore is currently unoptimized (Mar 2013). This means there are
  a number of hotspots causing performance issues. It is worth noting that the
  primary developers work with a proprietary datastore so Mongo performance has
  not been made a high priority up until recently. Patches welcome :)
</p>
</li>
</ul></div>
</div>
<div class="sect2">
<h3 id="_running_the_grr_http_server_in_apache">Running the GRR HTTP Server In Apache</h3>
<div class="paragraph"><p>TBD. User contributions welcome.
Using the wsgi hasn&#8217;t been thoroughly tested. If you test, please send feedback
to the dev list and we can try and fix things.</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_scheduling_flows_with_cron">Scheduling Flows with Cron</h2>
<div class="sectionbody">
<div class="paragraph"><p>The cron allows for scheduling actions to run regularly on the GRR server.
This is currently used to collect statistics and do cleanup on the database.</p></div>
<div class="paragraph"><p>The cron runs as a separate process cron.py. You can run it as often as you
like, e.g. every five minutes. It maintains internally how often each job needs
to run.</p></div>
<div class="paragraph"><p>The jobs that run are defined by CronJob classes, these are currently defined
in lib/aff4_objects/cronjobs.py</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_customizing_the_client">Customizing the client</h2>
<div class="sectionbody">
<div class="paragraph"><p>The client can be customized for deployment. There are two keys ways of doing
this:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
<p>
Repack the released client with a new configuration.
</p>
</li>
<li>
<p>
Rebuild the client from scratch (advanced users, set aside a few days the
first time)
</p>
</li>
</ol></div>
<div class="paragraph"><p>Doing a rebuild allows full reconfiguration, changing names and everything else.
A repack on the other hand limits what you can change. Each approach is
described below.</p></div>
<div class="sect2">
<h3 id="_repacking_the_client_with_a_new_configuration">Repacking the Client with a New Configuration.</h3>
<div class="paragraph"><p>Changing basic configuration parameters can be done by editing the config file
(default /etc/grr/grr-server.conf) and then using the config_updater or
client_build script to repack the binaries.
This allows for changing basic configuration parameters such as the URL
the client reports back to.</p></div>
<div class="paragraph"><p>To repack all clients with a new config and upload them to the datastore use
config_updater repack_clients.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:$ sudo grr_config_updater repack_clients
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;

## Repacking GRR windows amd64 2.5.0.4 client
Packed to /usr/share/grr/executables/windows/installers/GRR_2.5.0.4_amd64.exe

## Uploading
Uploading Windows amd64 binary from /usr/share/grr/executables/windows/installer
s/GRR_2.5.0.4_amd64.exe
Uploaded to aff4:/config/executables/windows/installers/GRR_2.5.0.4_amd64.exe
db@host:$</tt></pre>
</div></div>
<div class="paragraph"><p>You can also repack a single client with a new config using the client_build.py
script. This is described in the section for building clients.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<img src="./images/icons/note.png" alt="Note" />
</td>
<td class="content">This builds by taking the template zip file, adding relevant configuration
files to the zip, then modifying the zip into a special self extracting zip
archive.</td>
</tr></table>
</div>
</div>
<div class="sect2">
<h3 id="_building_the_client">Building the Client.</h3>
<div class="paragraph"><p>Doing this is much harder than it should be due to a lot of dependencies and
moving parts. It is also a bit of a moving target so we keep the docs for this
on the wiki. See:</p></div>
<div class="ulist"><ul>
<li>
<p>
<a href="https://code.google.com/p/grr/wiki/BuildingWindowsClient">https://code.google.com/p/grr/wiki/BuildingWindowsClient</a>
</p>
</li>
<li>
<p>
<a href="https://code.google.com/p/grr/wiki/BuildingOSXClient">https://code.google.com/p/grr/wiki/BuildingOSXClient</a>
</p>
</li>
<li>
<p>
<a href="https://code.google.com/p/grr/wiki/BuildingLinuxClient">https://code.google.com/p/grr/wiki/BuildingLinuxClient</a>
</p>
</li>
</ul></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_deploying_custom_drivers_and_code">Deploying Custom Drivers and Code.</h2>
<div class="sectionbody">
<div class="paragraph"><p>Drivers, binaries or python code can be pushed from the server to the clients
to enable new functionality. This has a number of use cases, such as:</p></div>
<div class="ulist"><ul>
<li>
<p>
Upgrades. When you want to update the client you need to be able to push new
code.
</p>
</li>
<li>
<p>
Drivers. If you want to load a driver on the client system to do memory
analysis, you may need a custom driver per system (e.g. in the case of Linux
kernel differences.)
</p>
</li>
<li>
<p>
Protected functionality. If you have code that you want to deploy to deal with
 a specific case, you may not want that to be part of the client, and should
 only be deployed to specific clients.
</p>
</li>
</ul></div>
<div class="paragraph"><p>The code that is pushed from the server must be signed by the
executable_signing_private_key for python and binaries or the
driver_signing_private_key for drivers. These signatures
will be checked by the client to ensure they match before the code is used.</p></div>
<div class="paragraph"><p>What is actually sent to the client is the code or binary wrapped in a protobuf
which will contain a hash, a signature and some other configuration data.</p></div>
<div class="paragraph"><p>To sign code requires use of config_updater utility. In a secure environment the
signing may occur on a different box from the server, but the examples below
show the basic example.</p></div>
<div class="sect2">
<h3 id="_deploying_arbitrary_python_code">Deploying Arbitrary Python Code.</h3>
<div class="paragraph"><p>To execute an arbitrary python blob, you need to create a file with python code
that has the following attributes:
- Code in the file must work when executed by exec() in the context of GRR.
- Any return data that you want sent back to the server should be stored string
encoded in a variable called "magic_return_str".</p></div>
<div class="paragraph"><p>E.g. as a simple example. The following code modifies the clients poll_max
setting and pings test.com.</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.5
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><tt><span style="font-weight: bold"><span style="color: #000080">import</span></span> commands
status<span style="color: #990000">,</span> output <span style="color: #990000">=</span> commands<span style="color: #990000">.</span><span style="font-weight: bold"><span style="color: #000000">getstatusoutput</span></span><span style="color: #990000">(</span><span style="color: #FF0000">"ping -c 3 test.com"</span><span style="color: #990000">)</span>
FLAGS<span style="color: #990000">.</span>poll_max <span style="color: #990000">=</span> <span style="color: #993399">100</span>
magic_return_str <span style="color: #990000">=</span> <span style="color: #FF0000">"poll_max successfully set. ping output %s"</span> <span style="color: #990000">%</span> output</tt></pre></div></div>
<div class="paragraph"><p>This file then needs to be signed and converted into the protobuf format
required, and then needs to be uploaded to the data store. You can do this using
the following command line.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>grr_config_updater upload_python --file=myfile.py --platform=windows</tt></pre>
</div></div>
<div class="paragraph"><p>At the end of this you should see something like:</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>Uploaded successfully to aff4:/config/python_hacks/myfile.py</tt></pre>
</div></div>
<div class="paragraph"><p>The uploaded files live by convention in aff4:/config/python_hacks and are
viewable in the Manage Binaries section of the Admin UI.</p></div>
<div class="paragraph"><p>The ExecutePythonHack Flow is provided for executing the file on a client.</p></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<img src="./images/icons/note.png" alt="Note" />
</td>
<td class="content">Specifying arguments to a PythonHack is possible as well through the
py_args argument on the commandline, this can be useful for making them more
useful.</td>
</tr></table>
</div>
</div>
<div class="sect2">
<h3 id="_deploying_drivers">Deploying Drivers</h3>
<div class="paragraph"><p>Drivers are currently used in memory analysis. By default we use drivers
developed and released by the GRR team named "pmem". We currently have Apache
Licensed, tested drivers for OSX, Linux and Windows.</p></div>
<div class="paragraph"><p>The drivers are distributed with GRR but are also available from the Volatility
project in binary form at <a href="http://code.google.com/p/volatility/downloads/list">http://code.google.com/p/volatility/downloads/list</a>,
the source is stored in the scudette branch at
<a href="http://code.google.com/p/volatility/source/browse/#svn%2Fbranches%2Fscudette%2Ftools">http://code.google.com/p/volatility/source/browse/#svn%2Fbranches%2Fscudette%2Ftools</a>.</p></div>
<div class="paragraph"><p>Deploying a driver works much the same as deploying python code. We sign the
file, encode it in a protobuf and upload it to a specific place in the GRR
datastore. There is a shortcut to upload the existing memory drivers using
config updater.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host: ~$ sudo grr_config_updater load_memory_drivers
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
uploaded aff4:/config/drivers/darwin/memory/osxpmem
uploaded aff4:/config/drivers/windows/memory/winpmem.32.sys
uploaded aff4:/config/drivers/windows/memory/winpmem.64.sys
db@host:$</tt></pre>
</div></div>
<div class="admonitionblock">
<table><tr>
<td class="icon">
<img src="./images/icons/note.png" alt="Note" />
</td>
<td class="content">The signing we discuss here is independent of Authenticode driver signing,
which is also required by modern 64 bit Windows distributions.</td>
</tr></table>
</div>
<div class="paragraph"><p>Deploying this driver would normally be done using the LoadMemoryDriver flow.</p></div>
</div>
<div class="sect2">
<h3 id="_deploying_executables">Deploying Executables.</h3>
<div class="paragraph"><p>The GRR Agent provides an ExecuteBinaryCommand Client Action which allows us to
send a binary and set of command line arguments to be executed. The binary must
be signed using the executable signing key (config option
PrivateKeys.executable_signing_private_key).</p></div>
<div class="paragraph"><p>To sign an exe for execution use the config updater script.</p></div>
<div class="listingblock">
<div class="content">
<pre><tt>db@host:$ grr_config_updater upload_exe --file=/tmp/bazinga.exe -platform=windows
Using configuration &lt;ConfigFileParser filename="/etc/grr/grr-server.conf"&gt;
Uploaded successfully to /config/executables/windows/installers/bazinga.exe
db@host:$</tt></pre>
</div></div>
<div class="paragraph"><p>This uploads to the installers directory by default. But you can override with
the --dest_path option.</p></div>
</div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated 2013-04-06 00:55:09 CEST
</div>
</div>
</body>
</html>
